package com.harmonyos.zxing;

import com.google.zxing.journeyapps.barcodescanner.CameraPreview;
import com.google.zxing.journeyapps.barcodescanner.DecoratedBarcodeView;
import ohos.aafwk.ability.fraction.Fraction;
import ohos.aafwk.ability.fraction.FractionAbility;
import ohos.aafwk.ability.fraction.FractionManager;
import ohos.aafwk.ability.fraction.FractionScheduler;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.PageSlider;
import ohos.agp.components.PageSliderProvider;
import ohos.agp.components.TabList;
import ohos.agp.window.service.Window;
import ohos.agp.window.service.WindowManager;
import ohos.utils.PlainArray;

import java.util.Optional;

public class TabbedScanning extends FractionAbility implements TabList.TabSelectedListener, PageSlider.PageChangedListener {
    private PageSlider pageSlider;
    private SectionsPagerAdapter mSectionsPagerAdapter;
    private TabList tabList;
    private int curIndex = 0;
    private int lastIndex = -1;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        setUIContent(ResourceTable.Layout_ability_tabbed_scanning);
        WindowManager windowManager = WindowManager.getInstance();
        Window window = windowManager.getTopWindow().get();
        window.setTransparent(true);

        tabList = (TabList) findComponentById(ResourceTable.Id_tabList);
        pageSlider = (PageSlider) findComponentById(ResourceTable.Id_container);
        mSectionsPagerAdapter = new SectionsPagerAdapter(getFractionManager());
        pageSlider.setProvider(mSectionsPagerAdapter);

        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
            TabList.Tab tab = tabList.new Tab(this);
            tab.setText(mSectionsPagerAdapter.getPageTitle(i));
            tabList.addTab(tab);
        }

        tabList.addTabSelectedListener(this);
        pageSlider.addPageChangedListener(this);
        tabList.selectTabAt(0);
        pageSlider.setCurrentPage(0);
        setFractionVisible(0,true);
    }

    @Override
    public void onSelected(TabList.Tab tab) {
        int position = tab.getPosition();
        pageSlider.setCurrentPage(position);
    }

    @Override
    public void onUnselected(TabList.Tab tab) {

    }

    @Override
    public void onReselected(TabList.Tab tab) {

    }

    @Override
    public void onPageSliding(int i, float v, int i1) {

    }

    @Override
    public void onPageSlideStateChanged(int i) {

    }

    @Override
    public void onPageChosen(int i) {
        tabList.selectTabAt(i);
        setFractionVisible(lastIndex,false);
        curIndex = i;
        lastIndex = curIndex;
        setFractionVisible(curIndex,true);
    }

    private void setFractionVisible(int position,boolean visible) {
        if (position >= 0 && position < mSectionsPagerAdapter.getCount()) {
            Optional<Fraction> optionalFraction = mSectionsPagerAdapter.fractionPlainArray.get(position);
            if (optionalFraction.isPresent()) {
                Fraction fraction = optionalFraction.get();
                if (fraction instanceof ScanFraction) {
                    ((ScanFraction) fraction).setVisible(visible);
                } else if (fraction instanceof CameraFraction) {
                    ((CameraFraction) fraction).setVisible(visible);
                }
            }
        }
    }

    public class SectionsPagerAdapter extends PageSliderProvider {
        private FractionManager mFractionManager;
        public PlainArray<Fraction> fractionPlainArray;

        public SectionsPagerAdapter(FractionManager fractionManager) {
            mFractionManager = fractionManager;
            fractionPlainArray = new PlainArray<>(getCount());
        }

        @Override
        public int getCount() {
            return 2;
        }

        public Fraction getItem(int position) {
            if (position == 0) {
                return ScanFraction.newInstance();
            } else {
                return CameraFraction.newInstance();
            }
        }

        private Component getFractionComponent(ComponentContainer container, int position) {
            Fraction fraction;
            if (container.getId() == Component.ID_DEFAULT) {
                container.setId(container.getName().hashCode());
            }
            String key = container.getId() + ":" + position;
            Optional<Fraction> optionalFraction = mFractionManager.getFractionByTag(key);
            FractionScheduler fractionScheduler = mFractionManager.startFractionScheduler();
            if (optionalFraction.isPresent()) {
                fraction = optionalFraction.get();
                fractionScheduler.show(fraction);
            } else {
                fraction = getItem(position);
                fractionScheduler.add(container.getId(), fraction, key);
                fractionPlainArray.put(position,fraction);
            }
            fractionScheduler.submit();
            return fraction.getComponent();
        }

        @Override
        public Object createPageInContainer(ComponentContainer componentContainer, int i) {
            Component component = getFractionComponent(componentContainer, i);
            componentContainer.addComponent(component);
            return component;
        }

        @Override
        public void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) {
            componentContainer.removeComponent((Component) o);
        }

        @Override
        public boolean isPageMatchToObject(Component component, Object o) {
            return false;
        }

        @Override
        public String getPageTitle(int position) {
            switch (position) {
                case 0:
                    return "Scan";
                case 1:
                    return "Camera";
            }
            return null;
        }
    }

    public static class ScanFraction extends Fraction {
        private DecoratedBarcodeView barcodeView;
        private Component component;
        private boolean visible;

        public static ScanFraction newInstance() {
            return new ScanFraction();
        }

        @Override
        public Component getComponent() {
            return component;
        }

        @Override
        protected Component onComponentAttached(LayoutScatter scatter, ComponentContainer container, Intent intent) {
            component = scatter.parse(ResourceTable.Layout_fraction_tabbed_scanning, container, false);
            barcodeView = (DecoratedBarcodeView) component.findComponentById(ResourceTable.Id_barcode_view);
            return component;
        }

        public void setVisible(boolean visible) {
            this.visible = visible;
            if (visible) {
                onActive();
            } else {
                onInactive();
            }
        }

        @Override
        protected void onActive() {
            super.onActive();
            if (barcodeView != null && visible)
                barcodeView.resume();
        }

        @Override
        protected void onInactive() {
            super.onInactive();
            if (barcodeView != null && !visible)
                barcodeView.pauseAndWait();
        }
    }

    public static class CameraFraction extends Fraction {
        private CameraPreview cameraPreview;
        private ComponentContainer component;
        private boolean visible;

        public static CameraFraction newInstance() {
            return new CameraFraction();
        }

        @Override
        protected Component onComponentAttached(LayoutScatter scatter, ComponentContainer container, Intent intent) {
            component = (ComponentContainer) scatter.parse(ResourceTable.Layout_fraction_tabbed_camera, container, false);
            if (component != null) {

                for (int i = 0; i < component.getChildCount(); i++) {
                    Component child = component.getComponentAt(i);
                }
            }
            cameraPreview = (CameraPreview) component.findComponentById(ResourceTable.Id_camera_preview);
            return component;
        }

        @Override
        public Component getComponent() {
            return component;
        }

        public void setVisible(boolean visible) {
            this.visible = visible;
            if (visible) {
                onActive();
            } else {
                onInactive();
            }
        }

        @Override
        protected void onActive() {
            super.onActive();
            if (cameraPreview != null && visible)
                cameraPreview.resume();
        }

        @Override
        protected void onInactive() {
            super.onInactive();
            if (cameraPreview != null && !visible)
                cameraPreview.pauseAndWait();
        }
    }
}
